package Vue;

import ilog.concert.IloException;

import java.awt.BorderLayout;
import java.awt.Choice;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;



import Exception.ExceptionBadFileFormat;
import Methodes.Solution;

import Controleur.Controleur;



/**
 * Fenetre d'affichage de demarrage. Permet de charger des données et de lancer la résolution 
 * désirée.
 * @author ejouini
 *
 */
public class Start extends JFrame implements ActionListener {

	/** Variable contenant notre solution optimale au probléme. */
	private Solution solutionOptimale;

	/** Sélectionneur de fichier appelé lorsque l'on appuie sur le bouton 'Parcourir' */
	private JFileChooser choixFichier;

	/** Panel contenant tous les composants de notre fenêtre. */
	private JPanel panelPrincipal;

	/** JTextField ou apparait le chemin vers le fichier à charger. */
	private JTextField chemin;

	/** Controleur associé à cette fenetre. */
	private Controleur controleur;

	/** Listbox permettant de choisir le type de résolution. */
	private Choice resolutionMode;

	/**	Radio bouton de selection du type de donnees (ici binaire). */
	private JRadioButton btnDataBinaire;

	/** Radio bouton de selection du type de donnees (ici réelle).*/
	private JRadioButton btnDataReelle;
	
	/** Radio bouton de selection du type de donnees (ici le resultat de cvx).*/
	private JRadioButton btnDataCVX;

	/** Label indiquant si les donnees binaire ont ete chargées. */
	private JLabel lblDataBinaire;

	/** Label indiquant si les données réelles ont été chargées. */
	private JLabel lblDataReelle;
	
	/** Label indiquant si le résultat de CVX a été chargé. */
	private JLabel lblDataCVX;

	/** Groupe des boutons radio pour qu'un seul soit sélectionnable */
	private ButtonGroup groupeRadioBtn;

	/** Bouton de validation lancant la resolution avec la methode choisie. */
	private JButton btnValider;
	
	/** Label decrivant le choix du mode de resolution. */
	private JLabel lblMode;
	
	/**
	 * Constructeur qui initialise et dessine la fenêtre de chargement de données et 
	 * de selection du mode de résolution.
	 */
	public Start() {

		//*** Initialisation des composants ***//
		
		panelPrincipal = new JPanel(new GridLayout(5, 1));
		JButton btnParcourir = new JButton("Parcourir");
		choixFichier = new JFileChooser();
		btnValider = new JButton(">>> Process <<<");
		JButton btnCharger = new JButton("Charger");
		btnDataReelle = new JRadioButton("Données réelles");
		btnDataBinaire = new JRadioButton("Données binaires");
		btnDataCVX = new JRadioButton("Fichier résultat CVX");
		groupeRadioBtn = new ButtonGroup();
		lblDataReelle = new JLabel("Données non disponnibles");
		lblDataBinaire = new JLabel("Données non disponnibles");
		lblDataCVX = new JLabel("Résultats non disponibles");

		chemin = new JTextField(20);
		JMenuBar menuBar = new JMenuBar();
		JMenu menuFichier = new JMenu("Fichier");
		JMenuItem itemQuit = new JMenuItem("Quitter");
		resolutionMode = new Choice();

		JLabel lblTitre = new JLabel("  Veuillez choisir un fichier de données :");
		lblMode = new JLabel("Choisissez un mode : ");
		JPanel panelTitre = new JPanel(new BorderLayout());
		JPanel panelSaisie = new JPanel();
		JPanel panelMode = new JPanel();
		JPanel panelData = new JPanel(new GridLayout(3,2));
		

		//*** Configuration et agencement des composants ***//
		
		lblDataReelle.setForeground(Color.gray);
		lblDataBinaire.setForeground(Color.gray);
		lblDataCVX.setForeground(Color.gray);

		groupeRadioBtn.add(btnDataBinaire);
		groupeRadioBtn.add(btnDataReelle);
		groupeRadioBtn.add(btnDataCVX);

		resolutionMode.add("");
		resolutionMode.add("Variables Réelles : Formulation avec Recours (Cplex)");
		resolutionMode.add("Variables Réelles : Résolution par CVX");
		resolutionMode.add("Variables Binaires : Résolution exacte (Cplex)");
		resolutionMode.add("Variables Binaires : Résolution approché (Relaxation)");
		resolutionMode.add("Variables Binaires : Résolution approché (Recuit)");
		
		resolutionMode.setEnabled(false);
		
		lblMode.setForeground(Color.gray);
		
		menuFichier.add(itemQuit);
		menuBar.add(menuFichier);

		panelTitre.add(lblTitre, BorderLayout.CENTER);

		panelSaisie.add(chemin);
		panelSaisie.add(btnParcourir);
		panelSaisie.add(btnCharger);

		panelData.add(btnDataBinaire);
		panelData.add(lblDataBinaire);
		panelData.add(btnDataReelle);
		panelData.add(lblDataReelle);
		panelData.add(btnDataCVX);
		panelData.add(lblDataCVX);

		panelMode.add(lblMode);
		panelMode.add(resolutionMode);

		panelPrincipal.add(panelTitre);
		panelPrincipal.add(panelSaisie);
		panelPrincipal.add(panelData);
		panelPrincipal.add(panelMode);
		panelPrincipal.add(btnValider);

		//*** Mise en place des interactions ***//

		btnParcourir.addActionListener(this);
		btnParcourir.setActionCommand("Parcourir");
		btnCharger.addActionListener(this);
		btnCharger.setActionCommand("Charger");
		btnValider.addActionListener(this);
		btnValider.setActionCommand("Process");
		btnValider.setEnabled(false);
		btnValider.setPreferredSize(new Dimension(10,10));
		itemQuit.addActionListener(this);
		itemQuit.setActionCommand("Quitter");



		//*** Ajout des composants à la fenetre ***//
		
		this.add(panelPrincipal);
		this.setJMenuBar(menuBar);
		
		controleur = new Controleur();

		//*** Mise en forme de la fenetre principale ***//
		setSize(new Dimension(520, 330));
		this.setTitle("Projet Stochastique");
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.setVisible (true);
		this.setLocation(500, 200);
	}

	/**
	 * Méthode qui traite les actions sur la fenêtre.
	 */
	public void actionPerformed(ActionEvent e) {
		if(e.getActionCommand().equals("Parcourir")) {
			File f;
			try {
				f = new File(new File(".").getCanonicalPath());
				choixFichier.setCurrentDirectory(f);
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
			choixFichier.showOpenDialog(this); 
			if(choixFichier.getSelectedFile() != null && choixFichier.getSelectedFile().isFile()) {
				chemin.setText(choixFichier.getSelectedFile().toString());
			}


		} 
		// Click sur le bouton "Process" de lancement de la résolution
		else if(e.getActionCommand().equals("Process")) {	
			// Si on a choisi un mode de resolution binaire
			if(resolutionMode.getSelectedIndex() > 2) {
				if (controleur.dataIsNotNull("Binaire") ) {		// Verification que les data ont bien été chargées
					try {
						// On appel la fonction de resolution correspondant au mode choisis.
						if(resolutionMode.getSelectedIndex() == 3) {
							getSolutionExacte();
						} else if(resolutionMode.getSelectedIndex() == 4) {
							getSolutionParRelaxation();
						} else {
							getSolutionParRecuit();
						}
					}
					catch (IloException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}

					// On appel la fenetre d'affichage des résultats
					afficherResultat();
				}
			} 
			
			// Mode réel
			else if(resolutionMode.getSelectedIndex() == 1) { 
				// On appel la fonction de resolution correspondant au mode choisis.
				if(controleur.dataIsNotNull("Reel")) {
					try {
						getSolutionParRecours();
					} catch (IloException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					// On appel la fenetre d'affichage des résultats
					afficherResultat();
				} 
				else
					JOptionPane.showMessageDialog(this, "Veuillez charger des données.", "Erreur", JOptionPane.ERROR_MESSAGE);

			}
			
			// Mode CVX
			else if (resolutionMode.getSelectedIndex() == 2) { 
				if(controleur.dataIsNotNull("CVX")) {
					try {
						getSolutionParCVX();
					} catch (IloException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					// On appel la fenetre d'affichage des résultats
					afficherResultat();
				}
				else 
					JOptionPane.showMessageDialog(this, "Veuillez charger le fichier résultat CVX.", "Erreur", JOptionPane.ERROR_MESSAGE);
			}
			else 
				JOptionPane.showMessageDialog(this, "Veuillez selectionner un mode de résolution.", "Erreur", JOptionPane.ERROR_MESSAGE);

		}  else if (e.getActionCommand().equals("Quitter")) {
			this.dispose();
		} 
		
		// Si on cherche à charger des données
		else if (e.getActionCommand().equals("Charger")) {
			try {
				
				// Données réelles à charger
				if ( (btnDataReelle.isSelected()) && (chemin.getText().length() != 0)) {
					if (controleur.dataIsNotNull("Reel")) 
						controleur.resetDataReel();
					readData(chemin.getText(), "Reel");
					lblDataReelle.setText("Données chargées");
					lblDataReelle.setForeground(Color.GREEN);
					lblMode.setForeground(Color.black);
					resolutionMode.setEnabled(true);
					btnValider.setEnabled(true);
					chemin.setText("");

				}
				// Données binaire à charger
				else if ((btnDataBinaire.isSelected()) && (chemin.getText().length() != 0)) {
					if (controleur.dataIsNotNull("Binaire")) 
						controleur.resetDataBinaire();
					readData(chemin.getText(), "Binaire");
					lblDataBinaire.setText("Données chargées");
					lblDataBinaire.setForeground(Color.GREEN);
					lblMode.setForeground(Color.black);
					resolutionMode.setEnabled(true);
					btnValider.setEnabled(true);
					chemin.setText("");
				}
				// Résultats de CVX à charger
				else if ((btnDataCVX.isSelected()) && (chemin.getText().length() != 0)) {
					if (controleur.dataIsNotNull("CVX")) 
						controleur.resetDataCVX();
					readData(chemin.getText(), "CVX");
					lblDataCVX.setText("Données chargées");
					lblDataCVX.setForeground(Color.GREEN);
					lblMode.setForeground(Color.black);
					resolutionMode.setEnabled(true);
					btnValider.setEnabled(true);
					chemin.setText("");
				}
				else if(chemin.getText().length() == 0)
					JOptionPane.showMessageDialog(this, "Veuillez choisir un fichier", "Erreur", JOptionPane.ERROR_MESSAGE);
				else
					JOptionPane.showMessageDialog(this, "Veuillez selectionner le type de données à charger.", "Erreur", JOptionPane.ERROR_MESSAGE);

			} catch (ExceptionBadFileFormat e1) {
				JOptionPane.showMessageDialog(this, "Le fichier ne respecte pas le format", "Erreur", JOptionPane.ERROR_MESSAGE);
			}
		}

	}

	/**
	 * Methode qui affiche le resultat obtenu à partir du fichier résultat généré par CVX.
	 * La solution obtenue est ensuite stockée dans la variable solutionOptimale. 
	 * @throws IloException 
	 */
	private void getSolutionParCVX() throws IloException {
		solutionOptimale = controleur.getSolutionParCVX();
	}

	/**
	 * Methode qui lance la resolution du problème par relaxation.
	 * La solution obtenue est ensuite stockée dans la variable solutionOptimale.
	 * @throws IloException 
	 */
	private void getSolutionParRelaxation() throws IloException {
		solutionOptimale = controleur.getSolutionParRelaxation();
	}

	/**
	 * Methode qui lance la resolution du probléme exacte par cplex.
	 * La solution obtenue est ensuite stockée dans la variable solutionOptimale.
	 * @throws IloException 
	 */
	private void getSolutionExacte() throws IloException {
		solutionOptimale = controleur.getSolutionExacte();
	}

	/**
	 * Methode qui lance la resolution du probléme avec recours (cplex).
	 * La solution obtenue est ensuite stockée dans la variable solutionOptimale.
	 * @throws IloException 
	 */
	private void getSolutionParRecours() throws IloException {
		solutionOptimale = controleur.getSolutionParRecours();	
	}

	/**
	 * Methode qui lance la resolution du probléme par la méthode du recuit simulé.
	 * La solution obtenue est ensuite stockée dans la variable solutionOptimale.
	 * @throws IloException 
	 */
	private void getSolutionParRecuit() throws IloException {
		solutionOptimale = controleur.getSolutionParRecuit();
	}

	/**
	 * Méthode permettant de lancer la récupération des données contenus dans le fichier selectionné.
	 * @param fichier : fichier de donnees a lire.
	 * @throws InvalidFormatException
	 * @throws IOException
	 */
	private void readData(String fichier, String mode) throws ExceptionBadFileFormat {
		controleur.lireDonnees(fichier, mode);
	}

	
	/**
	 * Méthode permettant d'afficher la fenêtre de résultat pour la résolution de notre problème.
	 */
	private void afficherResultat() {
		this.setVisible(false);
		Result resultat = new Result(this, solutionOptimale);
	}

}
